/*
 * mysocket.c
 *
 *  Created on: Nov 27, 2012
 *      Author: root
 */

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/net.h>
#include <linux/in.h>
#include <asm/uaccess.h>

#include "tutorfs.h"

struct socket * set_up_client_socket(unsigned int IP_addr, int port_no) {
	struct socket * clientsock;
	struct sockaddr_in sin;
	int error, i;

	/* First create a socket */
	error = sock_create(PF_INET,SOCK_STREAM,IPPROTO_TCP,&clientsock);
	if (error < 0) {
		printk("Error during creation of socket; terminating\n");
		return 0;
	}

	/* Now bind and connect the socket */
	sin.sin_family = AF_INET;
	sin.sin_addr.s_addr = htonl(IP_addr);
	sin.sin_port = htons(port_no);

	for (i = 0; i < 10; i++) {
		error = clientsock->ops->connect(clientsock, (struct sockaddr*) &sin,
				sizeof(sin), 0);
		if (error < 0) {
			printk(
					"Error connecting client socket to server: %i, retrying .. %d \n",
					error, i);
			if (i == 10 - 1) {
				printk("Giving Up!\n");
				return 0;
			}
		} else
			break;	//connected
	}

	return clientsock;

}
/*
 Sendbuffer sends "Length" bytes from "Buffer" through the socket "sock".


 */

size_t send_buffer(struct socket *sock, const byte *Buffer, size_t Length) {
	struct msghdr msg;
	mm_segment_t oldfs;	 // mm_segment_t is just a long
	struct iovec iov;	 // structure containing a base addr. and length
	int len2;

//printk("Entering SendBuffer\n");

	msg.msg_name = 0;
	msg.msg_namelen = 0;
	msg.msg_iov = &iov;
	msg.msg_iovlen = 1;	 //point to be noted
	msg.msg_control = NULL;
	msg.msg_controllen = 0;

	msg.msg_flags = MSG_NOSIGNAL;	 //0/*MSG_DONTWAIT*/;

	iov.iov_base = (byte*) Buffer;	 // as we know that iovec is
	iov.iov_len = (__kernel_size_t) Length;	// nothing but a base addr and length

// #define get_fs() (current_thread_info()->addr_limit)
// similar for set_fs;
	/*
	 Therefore this line sets the "fs" to KERNEL_DS and saves its old value
	 */
	oldfs = get_fs();
	set_fs(KERNEL_DS);

	/* Actual Sending of the Message */
	len2 = sock_sendmsg(sock, &msg, (size_t) (Length));

	/* retrieve the old value of fs (whatever it is)*/
	set_fs(oldfs);

	return len2;
}

/*
 Recieves data from the socket "sock" and puts it in the 'Buffer'.
 Returns the length of data recieved

 The Calling function must do a:
 Buffer = (char*) get_free_page(GFP_KERNEL);
 or a kmalloc to allocate kernel's memory
 (or it can use the kernel's stack space [very small] )

 */

size_t recv_buffer(struct socket *sock, byte *Buffer, size_t Length) {
	struct msghdr msg;
	struct iovec iov;

	int len;
	mm_segment_t oldfs;

	/* Set the msghdr structure*/
	msg.msg_name = 0;
	msg.msg_namelen = 0;
	msg.msg_iov = &iov;
	msg.msg_iovlen = 1;
	msg.msg_control = NULL;
	msg.msg_controllen = 0;
	msg.msg_flags = 0;

	/* Set the iovec structure*/
	iov.iov_base = (void *) &Buffer[0];
	iov.iov_len = (size_t) Length;

	/* Recieve the message */
	oldfs = get_fs();
	set_fs(KERNEL_DS);
	len = sock_recvmsg(sock, &msg, Length, 0/*MSG_DONTWAIT*/);// let it wait if there is no message
	set_fs(oldfs);

//	if ((len!=-EAGAIN)&&(len!=0))
//	 printk("RecvBuffer Recieved %i bytes \n",len);

	return len;
}

void release_socket(struct socket *sock) {
	sock->ops->release(sock);
}
